// reactive
const isObject = val => val !== null && typeof val === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target, key)

export function reactive(target) {
    if (!isObject(target)) return target

    const handle = {
        get(target, key, receiver) {
            // console.log('==get:', key);
            // 收集依赖
            track(target, key)
            // 相当于res = target[key],receiver改变target的this指向
            const res = Reflect.get(target, key, receiver)

            return convert(res)
        },
        set(target, key, val, receiver) {
            const oldVal = Reflect.get(target, key, receiver)
            let res = true//Proxy的set方法必须默认返回true

            if (oldVal !== val) {
                // 相当于target[key] = val
                res = Reflect.set(target, key, val, receiver)
                // 触发更新
                trigger(target, key)
                // console.log('==set:', key, val);
            }
            return res
        },
        deleteProperty(target, key) {
            const hasKey = hasOwn(target, key)
            // 相当于 delete target[key]
            const res = Reflect.deleteProperty(target, key)
            if (hasKey && res) {
                // console.log('==delete:', key);
            }
            return res
        }
    }
    return new Proxy(target, handle)
}

let activeEffect = null
export function effect(callback) {
    activeEffect = callback
    callback()// 访问响应式对象属性，去收集依赖
    activeEffect = null

}

let targetMap = new WeakMap()
// 跟踪
function track(target, key) {
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, (dep = new Set()))
    }
    dep.add(activeEffect)
}

// 发动
function trigger(target, key) {
    const depsMap = targetMap.get(target)
    if (!depsMap) return
    const dep = depsMap.get(key)
    if (dep) {
        dep.forEach(effect => {
            console.log(effect);
            effect()
        });
    }
}

export function ref(raw) {
    // 判断 raw 是否是 ref 创建的对象，如果是的话直接返回
    if (isObject(raw) && raw.__v_isRef) return

    let value = convert(raw)
    const r = {
        __v_isRef: true,
        get value() {
            track(r, 'value')
            return value
        },
        set value(newVal) {
            if (newVal !== value) {
                raw = newVal
                value = convert(raw)
                trigger(r, 'value')
            }
        }
    }
    return r
}

export function toRefs(proxy) {
    const ret = proxy instanceof Array ? new Array(proxy.length) : {}
    for (const key in proxy) {
        ret[key] = toProxyRef(proxy, key)
    }
    return ret
}
function toProxyRef(proxy, key) {
    const r = {
        __v_isRef: true,
        get value() {
            return proxy[key]
        },
        set value(newVal) {
            proxy[key] = newVal
        }
    }
    return r
}

export function computed(getter) {
    const res = ref()
    effect(() => {
        return (res.value = getter())
    })
    return res
}